package com.uflower.order.service.impl;


import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.uflower.common.to.BrandTo;
import com.uflower.common.to.UserLoginTo;
import com.uflower.common.utils.R;
import com.uflower.order.constant.OrderConstant;
import com.uflower.order.constant.enume.OrderStatusEnum;
import com.uflower.order.entity.OrderItemEntity;
import com.uflower.order.exception.OrderSubmitException;
import com.uflower.order.feign.ProductFeignService;
import com.uflower.order.feign.UserFeignService;
import com.uflower.order.interceptor.LoginUserInterceptor;
import com.uflower.order.service.CartService;
import com.uflower.order.service.OrderItemService;
import com.uflower.order.test.MyOrderVos;
import com.uflower.order.test.MyOrderVosFactory;
import com.uflower.order.to.*;
import com.uflower.order.vo.*;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.uflower.common.utils.PageUtils;
import com.uflower.common.utils.Query;

import com.uflower.order.dao.OrderDao;
import com.uflower.order.entity.OrderEntity;
import com.uflower.order.service.OrderService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("orderService")
public class OrderServiceImpl extends ServiceImpl<OrderDao, OrderEntity> implements OrderService {

    @Autowired
    UserFeignService userFeignService;
    @Autowired
    ProductFeignService productFeignService;
    @Autowired
    CartService cartService;
    @Autowired
    OrderItemService orderItemService;
    @Autowired
    StringRedisTemplate redisTemplate;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Override
    public OrderEntity getOrderByOrderSn(String orderSn) {
        return  this.getOne(new QueryWrapper<OrderEntity>().eq("order_sn",orderSn));
    }

    @Override
    public void closeOrder(OrderEntity orderEntity) {
        OrderEntity entity = this.getById(orderEntity.getId());
        if(entity.getStatus() == OrderStatusEnum.CREATE_NEW.getCode()){
            OrderEntity update = new OrderEntity();
            update.setId(entity.getId());
            update.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(update);
            //发给mq,库存解锁
           // rabbitTemplate.convertAndSend("order-event-exchange","order.release.other",orderEntity);
        }
    }

    @Override
    public void closeOrder(String orderSn) {
        OrderEntity entity = getOrderByOrderSn(orderSn);
        if(entity.getStatus() == OrderStatusEnum.CREATE_NEW.getCode()){
            OrderEntity update = new OrderEntity();
            update.setId(entity.getId());
            update.setStatus(OrderStatusEnum.CANCLED.getCode());
            this.updateById(update);
            //发给mq,库存解锁
            // rabbitTemplate.convertAndSend("order-event-exchange","order.release.other",orderEntity);
        }
    }

    @Override
    public List<OrderCenterOrderVo> queryCurrentUserOrders(Integer status) {
        MyOrderVos myOrderVos = MyOrderVosFactory.buildOrderVos(status);
        return myOrderVos.getOrders();
    }

    ThreadLocal<OrderSubmitVo> submitVoThreadLocal = new ThreadLocal<>();
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<OrderEntity> page = this.page(
                new Query<OrderEntity>().getPage(params),
                new QueryWrapper<OrderEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public OrderConfirmVo confirmOrder() {
        OrderConfirmVo orderConfirmVo = new OrderConfirmVo();
        //获取登录用户的信息
        UserLoginTo loginUser = LoginUserInterceptor.loginUser.get();
        orderConfirmVo.setUserId(loginUser.getId());
        // 1 查出购物车中勾选的商品信息 并更新价格信息
        List<CartItemVo> cartItemVos = cartService.getCheckedItems(loginUser.getId());
        List<OrderItemVo> orderItems = cartItemVos.stream().map(item -> {
            //更新价格
            BigDecimal price = productFeignService.getPrice(item.getSkuId());
            item.setPrice(price);
            OrderItemVo orderItem = new OrderItemVo();
            BeanUtils.copyProperties(item, orderItem);
            orderItem.setTotalPrice(item.getTotalPrice());
            if(item.getFullReduce()!= null&&item.getTotalPrice().compareTo(item.getFullReduce().getFullPrice()) == 1 ){
                orderItem.setReduce(item.getFullReduce().getReducePrice());
            }else{
                orderItem.setReduce(new BigDecimal("0"));
            }
            return orderItem;
        }).collect(Collectors.toList());
        orderConfirmVo.setItems(orderItems);
        //  2 计算出总价 优惠 运费
        BigDecimal totalPrice = new BigDecimal("0");
        BigDecimal totalReduce = new BigDecimal("0");
        BigDecimal payPrice = new BigDecimal("0");
        for (OrderItemVo orderItem : orderItems) {
            totalPrice = totalPrice.add(orderItem.getTotalPrice());
            totalReduce = totalReduce.add(orderItem.getReduce());
        }
        payPrice = payPrice.add(totalPrice).subtract(payPrice);
        orderConfirmVo.setTotalPrice(totalPrice);
        orderConfirmVo.setPayPrice(payPrice);
        // 3 查出用户的地址信息
        List<MemberAddressVo> address = userFeignService.getAddress(loginUser.getId());
        orderConfirmVo.setAdress(address);
        // 4 查出库存信息
        List<Long> skuIds = orderItems.stream().map(item -> {
            return item.getSkuId();
        }).collect(Collectors.toList());
        R r = productFeignService.getSkusHasStock(skuIds);
        List<SkuHasStockTo> skusHasStock = r.getData(new TypeReference<List<SkuHasStockTo>>() {
        }, "skusHasStock");
        Map<Long, Boolean> stocks = skusHasStock.stream().collect(Collectors.toMap(SkuHasStockTo::getSkuId, SkuHasStockTo::getHasStock));
        orderConfirmVo.setStocks(stocks);
        // 5 防止重复令牌
        String token = UUID.randomUUID().toString().replace("-", "");
        redisTemplate.opsForValue().set(OrderConstant.USER_ORDER_TOKEN_PREFIX+loginUser.getId(),token,30, TimeUnit.MINUTES);
        orderConfirmVo.setOrderToken(token);
        return orderConfirmVo;
    }

    @Override
    @Transactional
    public OrderSubmitResultVo submitOrder(OrderSubmitVo submitVo) {
        submitVoThreadLocal.set(submitVo);

        OrderSubmitResultVo response = new OrderSubmitResultVo();
        UserLoginTo loginUser = LoginUserInterceptor.loginUser.get();
        //比较令牌
        String orderToken = submitVo.getOrderToken();
        String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
        Long tokenCompareRes = redisTemplate.execute(
                new DefaultRedisScript<>(script, Long.class),
                Arrays.asList(OrderConstant.USER_ORDER_TOKEN_PREFIX + loginUser.getId()),
                orderToken
        );

        if(tokenCompareRes==1L){
            /**
             * 令牌验证通过、处理业务
             *   1、创建订单
             *   2、验价、
             *   3、锁库存
             */
            OrderCreateTo orderCreateTo = createOrder();
            BigDecimal payAmount = orderCreateTo.getOrder().getPayAmount();
            BigDecimal payPrice = submitVo.getPayPrice();
            if(Math.abs(payAmount.subtract(payPrice).doubleValue())>3){

                // 价格差异过大、应提醒用户重新下单
                response.setCode(20030);
                throw OrderSubmitException.PRICE_CHECK_ERR;
            }else{
                //验价通过
                //1.保存订单 数据
                saveOrder(orderCreateTo);
                //2. 远程扣减库存
                WareSkuReduceTo reduceTo = orderReduceStock(orderCreateTo);
                R reduceStockRes = productFeignService.orderReduceStock(reduceTo);
                if( reduceStockRes.getCode() != 0){
                    //库存扣减失败
                    throw OrderSubmitException.LOCK_STOCK_ERR;
                }

                //订单生成成功
                response.setCode(20000);
                response.setOrder(orderCreateTo.getOrder());

                //订单创建成功，发送消息 //3. 定时关单
                rabbitTemplate.convertAndSend("order-event-exchange","order.create.order",orderCreateTo.getOrder());

            }
        }else{
            //令牌验证失败
            response.setCode(20020);
            throw OrderSubmitException.TOKEN_CHECK_ERR;
        }
        return response;
    }

    @Override
    public List<OrderEntity> getOrdersById(Long userId) {
        List<OrderEntity> orderVos = baseMapper
                .selectList(new QueryWrapper<OrderEntity>().eq("user_id",userId));
        return orderVos;
    }

    private WareSkuReduceTo orderReduceStock(OrderCreateTo orderCreateTo) {
        WareSkuReduceTo reduceTo = new WareSkuReduceTo();
        reduceTo.setOrderSn(orderCreateTo.getOrder().getOrderSn());
        List<OrderItemVo> orderItemVos = orderCreateTo.getOrderItems().stream().map(item -> {
            OrderItemVo orderItemVo = new OrderItemVo();
            orderItemVo.setSkuId(item.getSkuId());
            orderItemVo.setCount(item.getSkuQuantity());
            orderItemVo.setTitle(item.getSkuName());
            return orderItemVo;
        }).collect(Collectors.toList());
        reduceTo.setOrderItemVos(orderItemVos);
        return reduceTo;
    }

    private void saveOrder(OrderCreateTo orderCreateTo) {
        OrderEntity order = orderCreateTo.getOrder();
        order.setModifyTime(new Date());
        order.setCreateTime(new Date());
        this.baseMapper.insert(order);

        List<OrderItemEntity> orderItems = orderCreateTo.getOrderItems();
        orderItemService.saveBatch(orderItems);
    }

    private OrderCreateTo createOrder(){
        OrderCreateTo orderTo = new OrderCreateTo();
        //订单号，用户ID
        String orderSn = IdWorker.getTimeId();
        OrderEntity orderEntity = new OrderEntity();
        orderEntity.setOrderSn(orderSn);
        UserLoginTo user = LoginUserInterceptor.loginUser.get();
        orderEntity.setUserId(user.getId());
        orderEntity.setUserUsername(user.getUsername());
        orderEntity.setStatus(OrderStatusEnum.CREATE_NEW.getCode());
        //收货信息
        OrderSubmitVo orderSubmitVo = submitVoThreadLocal.get();
        R fare = productFeignService.getFare(orderSubmitVo.getAddrId());
        FareTo fareTo = fare.getData(new TypeReference<FareTo>() {
        }, "fareTo");
        orderEntity.setFreightAmount(fareTo.getFare());
        orderEntity.setReceiverProvince(fareTo.getAddressVo().getProvince());
        orderEntity.setReceiverCity(fareTo.getAddressVo().getCity());
        orderEntity.setReceiverRegion(fareTo.getAddressVo().getRegion());
        orderEntity.setReceiverDetailAddress(fareTo.getAddressVo().getDetailAddress());
        orderEntity.setReceiverName(fareTo.getAddressVo().getName());
        orderEntity.setReceiverPhone(fareTo.getAddressVo().getPhone());
        orderEntity.setReceiverPostCode(fareTo.getAddressVo().getPostCode());

        List<CartItemVo> checkedCartItems = cartService.getCheckedItems(LoginUserInterceptor.loginUser.get().getId());
        List<OrderItemEntity> orderItems = checkedCartItems.stream().map(item -> {
            OrderItemEntity orderItemEntity = new OrderItemEntity();
            Long skuId = item.getSkuId();
            R spuInfoBySkuId = productFeignService.getSpuInfoBySkuId(skuId);
            SpuInfoTo spuInfoData = spuInfoBySkuId.getData(new TypeReference<SpuInfoTo>() {
            }, "spuInfo");
            //1、封装spu 数据
            if(spuInfoData != null){
                orderItemEntity.setSpuId(spuInfoData.getId());
                orderItemEntity.setSpuName(spuInfoData.getSpuName());
                R brandInfoById = productFeignService.getBrandInfoById(spuInfoData.getBrandId());
                BrandTo brand = brandInfoById.getData(new TypeReference<BrandTo>() {
                }, "brand");
                if(brand != null){
                    orderItemEntity.setSpuBrand(brand.getName());
                    orderItemEntity.setCategoryId(spuInfoData.getCatalogId());
                }
            }
            //2、封装sku 数据
            orderItemEntity.setSkuId(skuId);
            orderItemEntity.setSkuName(item.getTitle());
            orderItemEntity.setSkuPic(item.getImage());
            orderItemEntity.setSkuPrice(item.getPrice());
            orderItemEntity.setSkuQuantity(item.getCount());
            //3.封装销售属性
            String skuAttrValues = StringUtils.collectionToDelimitedString(item.getSkuAttrValues(), ";");
            orderItemEntity.setSkuAttrsVals(skuAttrValues);
            //4.计算价格
            orderItemEntity.setTotalAmount(item.getTotalPrice());
            orderItemEntity.setPromotionAmount(item.getReduce());
            //5 订单号
            orderItemEntity.setOrderSn(orderSn);
            return orderItemEntity;
        }).collect(Collectors.toList());
        orderTo.setOrderItems(orderItems);

        computePrice(orderEntity,orderItems);
        orderTo.setOrder(orderEntity);

        return orderTo;
    }

    private void computePrice(OrderEntity orderEntity, List<OrderItemEntity> orderItemEntities){
        BigDecimal total =  new BigDecimal("0.0");
        BigDecimal pay =  new BigDecimal("0.0");
        BigDecimal promotion =  new BigDecimal("0.0");
        BigDecimal freightAmount = orderEntity.getFreightAmount();
        for (OrderItemEntity orderItemEntity : orderItemEntities) {
            total = total.add(orderItemEntity.getTotalAmount());
            promotion = promotion.add(orderItemEntity.getPromotionAmount());
        }
        orderEntity.setTotalAmount(total);
        orderEntity.setPromotionAmount(promotion);
        orderEntity.setPayAmount(total.add(freightAmount).subtract(promotion));
        //设置删除状态(0-未删除，1-已删除)
        orderEntity.setDeleteStatus(0);
    }




    //查询用户拥有的订单
    private List<OrderCenterOrderVo> allOrdersByUser(){
        Long uid = LoginUserInterceptor.loginUser.get().getId();
        List<OrderEntity> allOrders = this.list(new QueryWrapper<OrderEntity>().eq("user_id", uid));
        List<OrderCenterOrderVo> orderCenterOrderVos = allOrders.stream().map(order -> {
            OrderCenterOrderVo orderCenterOrderVo = new OrderCenterOrderVo();
            orderCenterOrderVo.setOrderSn(order.getOrderSn());
            orderCenterOrderVo.setCreateTime(order.getCreateTime());
            orderCenterOrderVo.setStatus(order.getStatus());
            orderCenterOrderVo.setFreightAmount(order.getFreightAmount());
            orderCenterOrderVo.setPayAmount(order.getPayAmount());
            orderCenterOrderVo.setPromotionAmount(orderCenterOrderVo.getPromotionAmount());

            List<OrderItemEntity> list = orderItemService.getOrderItemsByOrderSn(order.getOrderSn());
            orderCenterOrderVo.setItems(list);
            return orderCenterOrderVo;
        }).collect(Collectors.toList());
        return orderCenterOrderVos;
    }
    //查询用户拥有的订单-- 待付款
    private List<OrderCenterOrderVo> unPayedOrdersByUser(){
        Long uid = LoginUserInterceptor.loginUser.get().getId();
        List<OrderEntity> allOrders = this.list(new QueryWrapper<OrderEntity>()
                .eq("user_id", uid)
                .eq("status",OrderStatusEnum.CREATE_NEW));

        List<OrderCenterOrderVo> orderCenterOrderVos = allOrders.stream().map(order -> {
            OrderCenterOrderVo orderCenterOrderVo = new OrderCenterOrderVo();
            orderCenterOrderVo.setOrderSn(order.getOrderSn());
            orderCenterOrderVo.setCreateTime(order.getCreateTime());
            orderCenterOrderVo.setStatus(order.getStatus());
            orderCenterOrderVo.setFreightAmount(order.getFreightAmount());
            orderCenterOrderVo.setPayAmount(order.getPayAmount());
            orderCenterOrderVo.setPromotionAmount(orderCenterOrderVo.getPromotionAmount());

            List<OrderItemEntity> list = orderItemService.getOrderItemsByOrderSn(order.getOrderSn());
            orderCenterOrderVo.setItems(list);
            return orderCenterOrderVo;
        }).collect(Collectors.toList());
        return orderCenterOrderVos;
    }
    //查询用户拥有的订单--已付款，待发货
    private List<OrderCenterOrderVo> unshippingOrdersByUser(){
        Long uid = LoginUserInterceptor.loginUser.get().getId();
        List<OrderEntity> allOrders = this.list(new QueryWrapper<OrderEntity>()
                .eq("user_id", uid)
                .eq("status",OrderStatusEnum.PAYED));
        List<OrderCenterOrderVo> orderCenterOrderVos = allOrders.stream().map(order -> {
            OrderCenterOrderVo orderCenterOrderVo = new OrderCenterOrderVo();
            orderCenterOrderVo.setOrderSn(order.getOrderSn());
            orderCenterOrderVo.setCreateTime(order.getCreateTime());
            orderCenterOrderVo.setStatus(order.getStatus());
            orderCenterOrderVo.setFreightAmount(order.getFreightAmount());
            orderCenterOrderVo.setPayAmount(order.getPayAmount());
            orderCenterOrderVo.setPromotionAmount(orderCenterOrderVo.getPromotionAmount());

            List<OrderItemEntity> list = orderItemService.getOrderItemsByOrderSn(order.getOrderSn());
            orderCenterOrderVo.setItems(list);
            return orderCenterOrderVo;
        }).collect(Collectors.toList());
        return orderCenterOrderVos;
    }
    //查询用户拥有的订单--已发货，待收货
    private List<OrderCenterOrderVo> unDeliveryOrdersByUser(){
        Long uid = LoginUserInterceptor.loginUser.get().getId();
        List<OrderEntity> allOrders = this.list(new QueryWrapper<OrderEntity>()
                .eq("user_id", uid)
                .eq("status",OrderStatusEnum.SENDEND));
        List<OrderCenterOrderVo> orderCenterOrderVos = allOrders.stream().map(order -> {
            OrderCenterOrderVo orderCenterOrderVo = new OrderCenterOrderVo();
            orderCenterOrderVo.setOrderSn(order.getOrderSn());
            orderCenterOrderVo.setCreateTime(order.getCreateTime());
            orderCenterOrderVo.setStatus(order.getStatus());
            orderCenterOrderVo.setFreightAmount(order.getFreightAmount());
            orderCenterOrderVo.setPayAmount(order.getPayAmount());
            orderCenterOrderVo.setPromotionAmount(orderCenterOrderVo.getPromotionAmount());

            List<OrderItemEntity> list = orderItemService.getOrderItemsByOrderSn(order.getOrderSn());
            orderCenterOrderVo.setItems(list);
            return orderCenterOrderVo;
        }).collect(Collectors.toList());
        return orderCenterOrderVos;
    }

    //查询用户拥有的订单--已取消
    private List<OrderCenterOrderVo> canceledOrdersByUser(){
        Long uid = LoginUserInterceptor.loginUser.get().getId();
        List<OrderEntity> allOrders = this.list(new QueryWrapper<OrderEntity>()
                .eq("user_id", uid)
                .eq("status",OrderStatusEnum.CANCLED));
        List<OrderCenterOrderVo> orderCenterOrderVos = allOrders.stream().map(order -> {
            OrderCenterOrderVo orderCenterOrderVo = new OrderCenterOrderVo();
            orderCenterOrderVo.setOrderSn(order.getOrderSn());
            orderCenterOrderVo.setCreateTime(order.getCreateTime());
            orderCenterOrderVo.setStatus(order.getStatus());
            orderCenterOrderVo.setFreightAmount(order.getFreightAmount());
            orderCenterOrderVo.setPayAmount(order.getPayAmount());
            orderCenterOrderVo.setPromotionAmount(orderCenterOrderVo.getPromotionAmount());

            List<OrderItemEntity> list = orderItemService.getOrderItemsByOrderSn(order.getOrderSn());
            orderCenterOrderVo.setItems(list);
            return orderCenterOrderVo;
        }).collect(Collectors.toList());
        return orderCenterOrderVos;
    }
}